home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 …SCII & the Runetime Code / ADC Developer CD (1992-07) (''Butch ASCII And The Runtime Code'')_iso / Dev.CD 199207.iso / Development Platforms / HyperCard Related / XCMDs & XFCNs / Help XFCN / source / help.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-03-19  |  23.3 KB  |  957 lines  |  [TEXT/MPS ]

  1. /* -----------------------------------------------------------------
  2.     File:            help.c
  3.                     XFCN to do 7.0 Help stuff
  4.     
  5.     Version:        see kVersionStr below
  6.     
  7.     History:        11-06-90 Alias    1.0d1 JRP    from volCheck.c
  8.                     11-12-90         1.0d2 JRP    put version stuff in vers.h
  9.                     11-13-90         1.0d3 JRP    add trap and gestalt checking
  10.                     11-14-90 Help    1.0d1 JRP    add findStringResId
  11.                                                 revise cmpStrtoResNum
  12.                                                 revise returnMsgNum
  13.                                                 remove alias-specific functions
  14.                                                 revise vers.h content and usage
  15.                     11-16-90 1.0d2 JRP    add ShowIfBalloon
  16.                     11-29-90 1.0d3 JRP    add gfun.c stuff
  17.                                         add getHotRect for ShowBalloon
  18.                     12-04-90 1.0d4 JRP    hotRect works only if the user has
  19.                                         show balloons turned on.
  20.                     01-18-91 1.1d1 JRP    major revision for 7.0b3
  21.                                         set ShowBalloon == ShowIfBalloon
  22.                                         add commands On, Off, and Disable
  23.                     02-19-91 1.2d1 JRP    additional parameters for Mr.Big
  24.     
  25.     Author:            John R. Powers, III
  26.                     GFX Group
  27.                     Instructional Products Department
  28.                     Apple Computer, Inc.
  29.                     (408) 974-9851
  30.                     (408) 395-1158
  31.                     AppleLink: JohnPowers
  32.     
  33.     Copyright:        see vers.h and "copyright" below.
  34.  
  35.     Computer:        Mac IIfx with System v7.0b3
  36.     
  37.     Compiler:        MPW v3.2
  38.                     MPW-C v3.2
  39.  
  40.     Usage:
  41.     
  42.         
  43.         Requires HyperCard version 1.2 or better.
  44.         There are HyperCard callbacks in this XFCN,
  45.         see gfun.c for callback information.
  46.         
  47.     Files:
  48.     
  49.         vers.h            header with version information
  50.         help.c            This source file
  51.         help.r            Rez source
  52.         gfun.c            source for using HyperCard globals
  53.         gfun.pro        prototypes for gfun.c
  54.         trap.c            source for using Gestalt
  55.         trap.pro        prototypes for trap.c
  56.         buildHelp        sets up and executes the make
  57.         makefileHelp    make file
  58.         helpLab            HyperCard stack for testing
  59.         
  60.     Full Build:
  61.     
  62.         see makefileHelp
  63.     
  64.     Parameter Usage for the ShowBalloon command:
  65.     
  66.         The following table shows the required parameters
  67.         for each type of ShowBalloon (added 1.2d1):
  68.         
  69.         type      cmd      text      tip      rect      entry      inset
  70.         
  71.         basic        1        2        3
  72.         
  73.         interm.A    1        2        3        4
  74.         
  75.         interm.B    1        2                4        5
  76.         
  77.         advanced    1        2                4        5        6
  78.         
  79.         basic        puts up balloon variant #0 at the tip location
  80.                     you specify.
  81.         
  82.         interm.A    puts up balloon variant #0 at the tip location
  83.                     you specify and passes a hot rect to HM.
  84.                     
  85.         interm.B    puts up the best balloon variant for the
  86.                     quadrant in which entry is located using
  87.                     a fixed inset for the tip. (added 1.2d1)
  88.         
  89.         advanced    puts up the best balloon variant for the
  90.                     quadrant in which entry is located and uses
  91.                     your inset for the tip. (added 1.2d1)
  92.  
  93.         
  94. ----------------------------------------------------------------- */
  95.  
  96. #include    <HyperXCmd.h>
  97. #include    <Types.h>
  98. #include    <CType.h>
  99. #include    <String.h>        /*    strcpy....    */
  100. #include    <Strings.h>        /*    c2pstr....    */
  101. #include    <Memory.h>
  102. #include    <ToolUtils.h>
  103. #include    <Resources.h>
  104. #include    <Packages.h>
  105. #include    <Files.h>
  106. #include    <Errors.h>
  107.  
  108. #include    <Balloons.h>
  109.  
  110. /*
  111.         Constants
  112. */
  113.  
  114. #define        kCterm                '\0'
  115. #define        kColon                ':'
  116. #define        kReturn                '\n'
  117. #define        kComma                ','
  118. #define        kSpace                ','
  119. #define        kCommaStr            ","
  120. #define        kReturnStr            "\n"
  121. #define        kSpaceStr            " "
  122. #define        kNoStringResource    "Err 00 Missing STR# for "
  123.  
  124. #include "vers.h"                /*     version and copyright info            */
  125.  
  126. enum                            /*    STR# indices                        */
  127.     {
  128.         ksCmdVersion=1,            /*    first of commands                    */
  129.         ksCmdHelp,
  130.         ksCmdShowBalloon,
  131.         ksCmdRemoveBalloon,
  132.         ksCmdShowIfBalloon,
  133.         ksCmdOn,
  134.         ksCmdOff,
  135.         ksCmdDisable,
  136.         ksHelpDesc,                /*    help description                    */
  137.         ksGlobalName,            /*    name of our HyperCard global        */
  138.         ksErrCommandWhere,        /*    first of error messages                */
  139.         ksErrCommandHuh,
  140.         ksErrParameters,
  141.         ksErrNoHelpMgr,
  142.         ksErrPointParam,
  143.         ksErrRectParam,
  144.         ksErrShowBalloon,
  145.         ksErrSetBalloons,
  146.         ksErrRemoveBalloon,
  147.         ksErrNoMemory,
  148.         ksErrStoreGlobal,
  149.         ksErrHelpNotOn,
  150.         ksErrNotYet
  151.     };
  152.  
  153. enum                            /*    parameter indices                    */
  154.     {
  155.         kParamCmd,                /*    command                                */
  156.         kParamText,                /*    help message text                    */
  157.         kParamLevel=kParamText,    /*    level number                        */
  158.         kParamTip,                /*    location for balloon tip            */
  159.         kParamRect,                /*    hot rectangle                        */
  160.         kParamEntry,            /*    point of entry into object            */
  161.         kParamOffset            /*    tip offset                            */
  162.     };
  163.                                 /*    The ShowBalloon command requires    */
  164.                                 /*    a minimum of 3, 4, or 5 parameters    */
  165. #define    kMinParamShowA        3
  166. #define    kMinParamShowB        5
  167.                                 /*    default tip offsets                    */
  168. #define    kOffsetHorz            10
  169. #define    kOffsetVert            10
  170.  
  171. enum                            /*    tip location variants in HM            */
  172.     {
  173.         kTip0=0,                /*    starts at 10 o'clock and goes CW    */
  174.         kTip1,
  175.         kTip2,
  176.         kTip3,
  177.         kTip4,
  178.         kTip5,
  179.         kTip6,
  180.         kTip7
  181.     };
  182.  
  183. /*
  184.         Macros
  185. */
  186.  
  187. #define        ABS(x)        (((x)<0)?(-(x)):(x))
  188.  
  189. /*
  190.         Structures
  191. */
  192.  
  193. typedef union {                    /*    for our Rect manipulations            */
  194.         Rect    altRect;
  195.         struct {
  196.             Point    topLeft;
  197.             Point    botRight;
  198.         } altPoints;
  199.     }    rectRecType, *rectPtrType, **rectHanType;
  200.  
  201. /*
  202.         Prototypes
  203. */
  204.  
  205. void addStrItemToList(char *, char *);
  206. void addNumItemToList(char *, long);
  207. short cmpStrtoResNum(Str255, short, short);
  208. void copyPtoCstr(char *, Str255);
  209. Handle copyStrToHand(char *);
  210. short equalPstr(Str255, Str255);
  211. short findStrResId(Str255);
  212. short getHotRect(XCmdPtr, Str255, short, Rect **);
  213. void getItemFromCList(char *, short, char *);
  214. void getItemFromPList(Str255, short, Str255);
  215. void handleToCstr(char *, Handle);
  216. void handleToNum(long *, Handle);
  217. void handleToPstr(Str255, Handle);
  218. short pointFromPstr(Point *, Str255);
  219. short rectFromPstr(Rect *, Str255);
  220. void returnMsgNum(XCmdPtr, short, short, long);
  221. void selectBalloon(Point *, short *, Point *, Rect *, Point *);
  222.  
  223. #include    "trap.pro"
  224. #include    "gfun.pro"
  225.  
  226. /*
  227.     DEBUG_MSG_HAN(msg, han) displays the message, msg,
  228.     and dumps the memory referenced by the handle, han.
  229. */
  230.  
  231. #define        DEBUG_MSG_HAN(msg, han)                            \
  232.             {                                                \
  233.                 char debugCstr[50],hexCstr[10];                \
  234.                 strcpy(debugCstr,msg);                        \
  235.                 strcat(debugCstr," ;dm ");                    \
  236.                 convertHanToHexStr(hexCstr, (Handle) han);    \
  237.                 strcat(debugCstr,hexCstr);                    \
  238.                 strcat(debugCstr, "^ ");                    \
  239.                 DebugStr((Str255)c2pstr(debugCstr));        \
  240.             }
  241. /*
  242.     Set kccDbAltRect true to debug (display) the
  243.     alternativeRect.
  244. */
  245.  
  246. #define        kccDbAltRect        false
  247.  
  248. /*
  249.         Main program and entry point for XFCN.
  250. */
  251.  
  252. pascal void    entryPoint(paramPtr)
  253. /*
  254. */
  255.  
  256.     XCmdPtr         paramPtr;        /*    the HyperCard connection    */
  257. {
  258.     char            resultStr[1024],
  259.                     copyright[]=kCopyrightStr;
  260.     Str255            command,
  261.                     pointPstr,
  262.                     globalNamePstr;
  263.     OSErr            err;
  264.     short            strResId,
  265.                     turnOn,
  266.                     tipProvided;
  267.     long            level;
  268.                                 /*    Help manager structures            */
  269.     HMMessageRecord    HMR;
  270.     Point            tip,
  271.                     entryLoc,
  272.                     tipInset;
  273.     Ptr                pTipProc;
  274.     short            theProc,
  275.                     variant,
  276.                     method;
  277.     Rect             *pQdRect;        /*    pointer to saved Rect        */
  278.     
  279.     *resultStr = kCterm;
  280.     if(paramPtr->paramCount<0)
  281.         return;                    /*    an event, ignore                */
  282.                                 /*    Get the string resource ID        */
  283.                                 /*    for our named STR#                */
  284.     strResId = findStrResId(kProgNameStr);
  285.     if(!strResId)
  286.     {                            /*    Oh-oh, our STR# is missing        */
  287.         strcpy(resultStr, kNoStringResource);
  288.         strcat(resultStr, kProgNameStr);
  289.         paramPtr->returnValue = copyStrToHand(resultStr);
  290.         return;
  291.     }
  292.                                 /*    get our global, if any            */
  293.     GetIndString(globalNamePstr, strResId, ksGlobalName);
  294.                                 /*    check for command                */
  295.     if(paramPtr->paramCount==0)
  296.     {
  297.         returnMsgNum(paramPtr, ksErrCommandWhere, strResId, 0);
  298.         return;
  299.     }
  300.     handleToPstr(command, paramPtr->params[kParamCmd]);
  301.                                 /*    version command?                */
  302.     if(cmpStrtoResNum(command, ksCmdVersion, strResId))
  303.     {
  304.         strcpy(resultStr, kProgNameStr);
  305.         strcat(resultStr, kSpaceStr);
  306.         strcat(resultStr, kVersionStr);
  307.         strcat(resultStr, kSpaceStr);
  308.         strcat(resultStr, kAuthorStr);
  309.         paramPtr->returnValue = copyStrToHand(resultStr);
  310.         return;
  311.     }
  312.                                 /*    help command?                    */
  313.     else if(cmpStrtoResNum(command, ksCmdHelp, strResId))
  314.     {
  315.         returnMsgNum(paramPtr, ksHelpDesc, strResId, 0);
  316.         return;
  317.     }
  318.     else if(!helpMgrPresent())    /*    check for Help Manager            */
  319.     {
  320.         returnMsgNum(paramPtr, ksErrNoHelpMgr, strResId, 0);
  321.         return;
  322.     }
  323.                                 /*    The following commands require    */
  324.                                 /*    the Help Manager                */
  325.  
  326.                                 /*    The show commands require        */
  327.                                 /*    that Balloon Help be enabled    */
  328.                                 /*    If it isn't, return right now.    */
  329.     if(!HMGetBalloons()
  330.         && (cmpStrtoResNum(command, ksCmdShowBalloon, strResId)
  331.             ||
  332.             cmpStrtoResNum(command, ksCmdShowIfBalloon, strResId)))
  333.     {
  334.         paramPtr->returnValue = nil;
  335.         return;
  336.     }
  337.                                 /*    Check for On or Off.            */
  338.                                 /*    If either, then the state of    */
  339.                                 /*    turnOn is the desired state.    */
  340.     if((turnOn = cmpStrtoResNum(command, ksCmdOn, strResId))
  341.         || cmpStrtoResNum(command, ksCmdOff, strResId))
  342.     {
  343.         if(err = HMSetBalloons(turnOn))
  344.         {
  345.             returnMsgNum(paramPtr, ksErrSetBalloons, strResId, err);
  346.             return;
  347.         }
  348.         else
  349.         {
  350.             paramPtr->returnValue = nil;
  351.             return;
  352.         }
  353.     }
  354.                                 /*    Disable, level?                    */
  355.     if(cmpStrtoResNum(command, ksCmdDisable, strResId))
  356.     {
  357.         if(paramPtr->paramCount<2)
  358.             level = 0;
  359.         else
  360.             handleToNum(&level, paramPtr->params[kParamText]);
  361.                                 /*    At this point, we need to make    */
  362.                                 /*    some neat call to HM to set the    */
  363.                                 /*    disable level (Right after        */
  364.                                 /*    Randy implements it.)            */
  365.         returnMsgNum(paramPtr, ksErrNotYet, strResId, 0);
  366.         return;
  367.     }
  368.  
  369.                                 /*    ShowBalloon    or                    */
  370.                                 /*    ShowIfBalloon command?            */
  371.     if(cmpStrtoResNum(command, ksCmdShowBalloon, strResId)
  372.         || cmpStrtoResNum(command, ksCmdShowIfBalloon, strResId))
  373.     {
  374.         if(paramPtr->paramCount<kMinParamShowA)
  375.         {                        /*    not enough parameters            */
  376.             returnMsgNum(paramPtr, ksErrParameters, strResId, 0);
  377.             return;
  378.         }
  379.                                 /*    pick off parameters                */
  380.                                 /*    first the message                */
  381.                                 /*    then the tip                    */
  382.         HMR.hmmHelpType = khmmString;
  383.         variant = kTip0;        /*    default balloon tip variant        */
  384.         handleToPstr((Str255) HMR.u.hmmString, paramPtr->params[kParamText]);
  385.         handleToPstr(pointPstr, paramPtr->params[kParamTip]);
  386.         if(tipProvided=(pointPstr[0]>0))
  387.         {
  388.             if(!pointFromPstr(&tip, pointPstr))
  389.             {
  390.                 returnMsgNum(paramPtr, ksErrPointParam, strResId, 0);
  391.                 return;
  392.             }
  393.             LocalToGlobal(&tip);
  394.         }
  395.         if(paramPtr->paramCount<=kMinParamShowA)
  396.             pQdRect = nil;        /*    no hot rect parameter            */
  397.         else                    /*    optional hot rect                */
  398.         {
  399.             if(!getHotRect(paramPtr, globalNamePstr, strResId, &pQdRect))
  400.             {                    /*    error, message already setup    */
  401.                 return;
  402.             }
  403.         }
  404.         if(!tipProvided)
  405.         {                        /*    empty point, need other params    */
  406.             if(paramPtr->paramCount<kMinParamShowB)
  407.             {                    /*    not enough parameters            */
  408.                 returnMsgNum(paramPtr, ksErrParameters, strResId, 0);
  409.                 return;
  410.             }
  411.                                 /*    entry point into object            */
  412.             handleToPstr(pointPstr, paramPtr->params[kParamEntry]);
  413.             if(!pointFromPstr(&entryLoc, pointPstr))
  414.             {
  415.                 returnMsgNum(paramPtr, ksErrPointParam, strResId, 0);
  416.                 return;
  417.             }
  418.             LocalToGlobal(&entryLoc);
  419.                                 /*    offset for balloon tip            */
  420.             handleToPstr(pointPstr, paramPtr->params[kParamOffset]);
  421.             if(pointPstr[0]==0)
  422.             {                    /*    empty, use defaults                */
  423.                 tipInset.h = kOffsetHorz;
  424.                 tipInset.v = kOffsetVert;
  425.             }
  426.             else if(!pointFromPstr(&tipInset, pointPstr))
  427.             {
  428.                 returnMsgNum(paramPtr, ksErrPointParam, strResId, 0);
  429.                 return;
  430.             }
  431.             selectBalloon(&tip, &variant, &entryLoc, pQdRect, &tipInset);
  432.         }    
  433.         pTipProc = nil;
  434.         theProc = 0;
  435.         method = kHMRegularWindow;
  436.         err = HMShowBalloon(HMR, tip, pQdRect, pTipProc,
  437.                                             theProc, variant, method);
  438.         if(err)
  439.         {
  440.             returnMsgNum(paramPtr, ksErrShowBalloon, strResId, err);
  441.             return;
  442.         }
  443.         paramPtr->returnValue = nil;
  444.         return;
  445.     }
  446.                                 /*    RemoveBalloon command?            */
  447.     if(cmpStrtoResNum(command, ksCmdRemoveBalloon, strResId))
  448.     {
  449.         if(HMIsBalloon())
  450.             if(err = HMRemoveBalloon())
  451.             {
  452.                 returnMsgNum(paramPtr, ksErrRemoveBalloon, strResId, err);
  453.                 return;
  454.             }
  455.         paramPtr->returnValue = nil;
  456.         return;
  457.     }
  458.     else
  459.     {
  460.         returnMsgNum(paramPtr, ksErrCommandHuh, strResId, 0);
  461.         return;
  462.     }
  463. }    /*    --------------------------------------------    entryPoint    */
  464.  
  465. /*
  466.         Functions
  467. */
  468.  
  469. void addNumItemToList(pList, num)
  470. /*
  471.     Add num to pList.
  472.     
  473.     Preceed each item with a comma.
  474.     The comma will not be added as
  475.     the first item in a string or
  476.     the first item in a line.
  477. */
  478.     char    *pList;
  479.     long    num;
  480. {
  481.     Str255    tempPstr;
  482.  
  483.     NumToString(num, tempPstr);
  484.     addStrItemToList(pList, p2cstr(tempPstr));
  485. }    /*    --------------------------------------------    addNumItemToList    */
  486.  
  487. void addStrItemToList(pList, pAdd)
  488. /*
  489.     Add pAdd to pList.
  490.     
  491.     Preceed each item with a comma.
  492.     The comma will not be added as
  493.     the first item in a string or
  494.     the first item in a line.
  495. */
  496.     char    *pList,
  497.             *pAdd;
  498. {
  499.     short    len;
  500.     
  501.     if(len=strlen(pList))
  502.         if(pList[len-1]!=kReturn)
  503.             strcat(pList, kCommaStr);
  504.     strcat(pList, pAdd);
  505. }    /*    --------------------------------------------    addStrItemToList    */
  506.  
  507. short cmpStrtoResNum(theString, theStrNum, strResId)
  508. /*
  509.  
  510.     08/17/90 1.0a2 MJP    new (GFXMenu)
  511.     11-14-90 1.0d1 JRP    add strResId as parameter
  512. */
  513.     Str255        theString;
  514.     short        theStrNum,
  515.                 strResId;
  516.     
  517. {
  518.     Str255        ResString;
  519.     
  520.     GetIndString(ResString, strResId, theStrNum);
  521.     return (equalPstr(ResString, theString));
  522. }    /*    --------------------------------------------    cmpStrtoResNum    */
  523.  
  524. void copyPtoCstr(Cstr, Pstr)
  525. /*
  526.     Copy the Pstr to the Cstr.
  527.     Don't do it in-place like p2cstr.
  528. */
  529.     Str255    Pstr;
  530.     char    *Cstr;
  531. {
  532.     short    i;
  533.     
  534.     for(i=1; i<=Pstr[0]; i++)
  535.         *Cstr++ = Pstr[i];
  536.     *Cstr = 0;
  537. }    /*    --------------------------------------- copyPtoCstr            */
  538.  
  539. Handle copyStrToHand(str)
  540. /*
  541.     Create a handle and copy the string to it.
  542.     Return the handle.
  543. */
  544.     char *str;
  545. {
  546.     Handle    newHndl;
  547.  
  548.     newHndl = (Handle) NewHandle((long) strlen(str) + 1);
  549.     HLock(newHndl);
  550.     strcpy(*newHndl, str);
  551.     HUnlock(newHndl);
  552.     return(newHndl);
  553. }    /*    --------------------------------------------    copyStrToHand        */
  554.  
  555. short equalPstr(s1, s2)
  556. /*
  557.     Compare s1 and s2.
  558.     If their contents are equal and they are of equal length, return TRUE.
  559.     Comparison is not case-sensitive.
  560. */
  561.     Str255    s1,
  562.             s2;
  563. {
  564.     short    i,
  565.             c1,
  566.             c2;
  567.     
  568.     if(s1[0]!=s2[0])
  569.         return false;
  570.     for(i=1; i<=s1[0]; i++)
  571.     {
  572.         c1 = tolower(s1[i]);
  573.         c2 = tolower(s2[i]);
  574.         if(c1!=c2)
  575.             return false;
  576.     }
  577.     return true;
  578. }    /*    --------------------------------------------    equalPstr            */
  579.  
  580. short findStrResId(resName)
  581. /*
  582.     Given the name of a STR# resource, return
  583.     its ID number.  This lets us use names instead
  584.     of ID's for tracking STR# resources.
  585. */
  586.     char    *resName;
  587. {
  588.     Handle    hRes;
  589.     short    theID;
  590.     ResType    theType;
  591.     Str255    theName;
  592.     
  593.     strcpy(theName, resName);
  594.     hRes = GetNamedResource('STR#', c2pstr(theName));
  595.     if(!hRes || ResError())
  596.         return 0;
  597.     GetResInfo(hRes, &theID, &theType, theName);
  598.     if(ResError()==resNotFound)
  599.         return 0;
  600.     else
  601.         return theID;
  602. }    /*    --------------------------------------------    findStrResId        */
  603.  
  604. short getHotRect(paramPtr, globalNamePstr, strResId, ppQdRect)
  605. /*
  606.     Return the pQdRect after extracting and converting
  607.     the HyperCard local rectangle on the parameter list.
  608.     
  609.     11-30-90 1.0d3 JRP    new
  610.     12-03-90 1.0d4 JRP    must return ppQdRect by reference, not value
  611.     
  612.     Return true if successful, false if error
  613. */
  614.     XCmdPtr         paramPtr;
  615.     Str255            globalNamePstr;
  616.     short            strResId;
  617.     Rect            **ppQdRect;        /*    pointer to the Rect Ptr        */
  618. {
  619.     Str255            rectPstr;        /*    HC rect in string form        */
  620.     Rect            hcRect;            /*    HC rect in HC rect form        */
  621.     Handle            hHelpRect;        /*    handle to saved Rect        */
  622.     rectPtrType        pHelpRect;        /*    local copy of rect pointer    */
  623.  
  624.     *ppQdRect = nil;
  625.     if(!fetchHanFromGlobal(paramPtr, globalNamePstr, &hHelpRect))
  626.     {                    /*    create storage for hot rect        */
  627.         hHelpRect = NewHandleClear(sizeof(rectRecType));
  628.         if(hHelpRect==nil || MemError())
  629.         {                /*    couldn't get memory for rect    */
  630.             returnMsgNum(paramPtr, ksErrNoMemory, strResId, 0);
  631.             return false;
  632.         }
  633.         MoveHHi(hHelpRect);
  634.         if(storeHanInGlobal(paramPtr, globalNamePstr, hHelpRect))
  635.         {                /*    error storing global            */
  636.             returnMsgNum(paramPtr, ksErrStoreGlobal, strResId, 0);
  637.             return false;
  638.         }
  639.     }
  640.                         /*    get optional HyperCard rect        */
  641.     handleToPstr(rectPstr, paramPtr->params[kParamRect]);
  642.     if(!rectFromPstr(&hcRect, rectPstr))
  643.     {
  644.         returnMsgNum(paramPtr, ksErrRectParam, strResId, 0);
  645.         return false;
  646.     }
  647.                         /*    our saved rect storage            */
  648.     HLock(hHelpRect);
  649.     pHelpRect = (rectPtrType) *hHelpRect;
  650.                         /*    HyperCard to QuickDraw Rect        */
  651.                         /*    copy to saved rect storage        */
  652.     pHelpRect->altRect.top = hcRect.left;
  653.     pHelpRect->altRect.left = hcRect.top;
  654.     pHelpRect->altRect.bottom = hcRect.right;
  655.     pHelpRect->altRect.right = hcRect.bottom;
  656.     #if    kccDbAltRect
  657.         DEBUG_MSG_HAN("After, QD Rect, Local", hHelpRect);
  658.     #endif
  659.                         /*    Local to Global Coordinates        */
  660.     LocalToGlobal(&(pHelpRect->altPoints.topLeft));
  661.     LocalToGlobal(&(pHelpRect->altPoints.botRight));
  662.     #if    kccDbAltRect
  663.         DEBUG_MSG_HAN("After, QD Rect, Global", hHelpRect);
  664.     #endif
  665.     *ppQdRect = (Rect *) pHelpRect;    /*    return ptr to rect    */
  666.     return true;        /*    success                            */
  667. }    /*    --------------------------------------------    getHotRect        */
  668.  
  669. void getItemFromCList(itemListCstr, itemNum, itemCstr)
  670. /*
  671.     Return the itemNum-th item in the itemListCstr.
  672.     Stops at end of string or Return character (end of HyperCard line).
  673.     Returns terminator if item not present.
  674.     Does not return any punctuation (comma or return).
  675. */
  676.     char    *itemListCstr;
  677.     short    itemNum;
  678.     char    *itemCstr;
  679. {
  680.     short    itemCnt=1;
  681.  
  682.                                     /*    Count commas to get itemNum-th item    */
  683.     while(itemCnt<itemNum && *itemListCstr!=0 && *itemListCstr!=kReturn)
  684.         if(*itemListCstr++==kComma)
  685.             itemCnt++;
  686.                                     /*    Copy itemNum-th item                */
  687.                                     /*    skip leading spaces                    */
  688.     if(itemCnt==itemNum)
  689.     {
  690.         while(*itemListCstr!=0 && *itemListCstr!=kReturn && *itemListCstr==kSpace)
  691.             itemListCstr++;
  692.         while(*itemListCstr!=0 && *itemListCstr!=kReturn && *itemListCstr!=kComma)
  693.             *itemCstr++ = *itemListCstr++;
  694.     }
  695.     *itemCstr = kCterm;
  696.         
  697. }    /*    --------------------------------------------    getItemFromCList        */
  698.  
  699. void getItemFromPList(itemListPstr, itemNum, itemPstr)
  700. /*
  701.     Return the itemNum-th item in the itemListPstr
  702. */
  703.     Str255    itemListPstr;
  704.     short    itemNum;
  705.     Str255    itemPstr;
  706. {
  707.     short    i=1,
  708.             j=0,
  709.             itemCnt=1;
  710.                                     /*    Count commas to get itemNum-th item    */
  711.     while(itemCnt<itemNum && i<itemListPstr[0])
  712.         if(itemListPstr[i++]==kComma)
  713.             itemCnt++;
  714.                                     /*    Copy itemNum-th item                */
  715.     if(itemCnt==itemNum)
  716.         while(i<=itemListPstr[0] && itemListPstr[i]!=kComma)
  717.             itemPstr[++j] = itemListPstr[i++];
  718.     itemPstr[0] = j;
  719. }    /*    --------------------------------------------    getItemFromPList        */
  720.  
  721. void handleToCstr(str, hndl)
  722. /*
  723.     Return a copy of the string contained in the handle.
  724.     If the handle is NIL, return an empty string.
  725. */
  726.     char    *str;
  727.     Handle    hndl;
  728. {
  729.     if(hndl==nil)
  730.         *str = kCterm;
  731.     else
  732.     {
  733.         HLock(hndl);
  734.         strcpy(str, *hndl);
  735.         HUnlock(hndl);
  736.     }
  737. }    /*    --------------------------------------------    handleToCstr        */
  738.  
  739. void handleToNum(num, hndl)
  740. /*
  741.     Return the number contained the string contained in the handle.
  742.     If the handle is NIL, return zero.
  743.     
  744.     Don't want to convert the handle string from C-string to
  745.     Pascal string in-place.  Copy to a local string first.
  746. */
  747.     long    *num;
  748.     Handle    hndl;
  749. {
  750.     char    str[32];
  751.     
  752.     if(hndl==nil)
  753.         *num = 0;
  754.     else
  755.     {
  756.         HLock(hndl);
  757.         strcpy((char *)str, *hndl);
  758.         HUnlock(hndl);
  759.         StringToNum(c2pstr(str), num);
  760.     }
  761. }    /*    --------------------------------------------    handleToNum        */
  762.  
  763. void handleToPstr(str, hndl)
  764. /*
  765.     Return a copy of the string contained in the handle.
  766.     If the handle is NIL, return an empty string.
  767. */
  768.     Str255    str;
  769.     Handle    hndl;
  770. {
  771.     if(hndl==nil)
  772.         str[0] = 0;
  773.     else
  774.     {
  775.         HLock(hndl);
  776.         strcpy((char *)str, *hndl);
  777.         HUnlock(hndl);
  778.         c2pstr(str);
  779.     }
  780. }    /*    --------------------------------------------    handleToPstr        */
  781.  
  782. short pointFromPstr(tip, pointPstr)
  783. /*
  784.     Pass a Pascal string containing two coordinates
  785.     in the form "h,v".  The point will be returned
  786.     in tip.
  787.     
  788.     true is returned if successful.
  789.     false if an error.
  790. */
  791.     Point    *tip;
  792.     Str255    pointPstr;
  793. {
  794.     Str255        pointHPstr,
  795.                 pointVPstr;
  796.     long        tempLong;
  797.     
  798.     getItemFromPList(pointPstr, 1, pointHPstr);
  799.     getItemFromPList(pointPstr, 2, pointVPstr);
  800.     if(pointHPstr[0]==0 || pointVPstr[0]==0)
  801.         return false;
  802.     StringToNum(pointHPstr, &tempLong);
  803.     tip->h = tempLong;
  804.     StringToNum(pointVPstr, &tempLong);
  805.     tip->v = tempLong;
  806.     return true;
  807. }    /*    --------------------------------------------    pointFromPstr        */
  808.  
  809. short rectFromPstr(theRect, rectPstr)
  810. /*
  811.     Pass a Pascal string containing a rect
  812.     in the form "t,l,b,r".  The rect will be returned
  813.     in theRect.
  814.     
  815.     true is returned if successful.
  816.     false if an error.
  817. */
  818.     Rect    *theRect;
  819.     Str255    rectPstr;
  820. {
  821.     Str255        rectItemPstr;
  822.     long        tempLong;
  823.     short        i;
  824.     
  825.     for(i=1; i<=4; i++)
  826.     {
  827.         getItemFromPList(rectPstr, i, rectItemPstr);
  828.         if(rectItemPstr[0]==0)
  829.             return false;
  830.         StringToNum(rectItemPstr, &tempLong);
  831.         switch(i)
  832.         {
  833.             case 1:
  834.                 theRect->top = tempLong;
  835.                 break;
  836.             case 2:
  837.                 theRect->left = tempLong;
  838.                 break;
  839.             case 3:
  840.                 theRect->bottom = tempLong;
  841.                 break;
  842.             case 4:
  843.                 theRect->right = tempLong;
  844.                 break;
  845.         }
  846.     }
  847.     return true;
  848. }    /*    --------------------------------------------    rectFromPstr        */
  849.  
  850. void returnMsgNum(paramPtr, strNum, strResId, num)
  851. /*
  852.     Given the STR# number and a number,
  853.     place the string and the number
  854.     in the return to HyperCard.
  855.     The num is optional, if 0 then it is not placed.
  856.     No space or punctuation is added between the string
  857.     and the num.
  858.     
  859.     11-14-90 1.0d1 JRP    add strResId as a parameter
  860.     11-30-90 1.0d3 JRP    append num directly rather than addNumItemToList
  861. */
  862.     XCmdPtr     paramPtr;        /*    the HyperCard connection        */
  863.     short        strNum,
  864.                 strResId;
  865.     long        num;
  866. {
  867.     Str255        resPstr,
  868.                 tempPstr;
  869.     char        resultStr[256];
  870.     
  871.     GetIndString(resPstr, strResId, strNum);
  872.     strcpy(resultStr, p2cstr(resPstr));
  873.     if(num!=0)
  874.     {
  875.         NumToString(num, tempPstr);
  876.         strcat(resultStr, p2cstr(tempPstr));
  877.     }
  878.     paramPtr->returnValue = copyStrToHand(resultStr);
  879. }    /*    --------------------------------------------    returnMsgNum    */
  880.  
  881. void selectBalloon(pTipLoc, pVariant, pEntryLoc, pObjRect, pTipInset)
  882. /*
  883.     Calculate the pTipLoc and balloon tip pVariant
  884.     given:
  885.             pEntryLoc    cursor location in object
  886.             pObjRect    the object rectangle
  887.             pTipInset    the inset desired for the tip
  888.     
  889.     by computing which quadrant the pEntryLoc is in
  890.     and, from that and the pObjRect, generating a
  891.     balloon tip location, pTipLoc, and balloon tip
  892.     pVariant that will not obscure the object.
  893.     
  894.     If pTipInset.h!=pTipInset.v, this function will select
  895.     a balloon pVariant that will minimize obscuring
  896.     the pObjRect.
  897.     
  898.     
  899.     All coordinates are global.
  900.     You're right, pEntryLoc and pTipInset did not have
  901.     to be passed as pointers.  But here they are anyway.
  902. */
  903.     Point    *pTipLoc;
  904.     short    *pVariant;
  905.     Point    *pEntryLoc;
  906.     Rect    *pObjRect;
  907.     Point    *pTipInset;
  908. {
  909.     Point    middle;
  910.                                 /*    divide object into quadrants        */
  911.     middle.v = pObjRect->top
  912.                 + ((ABS(pObjRect->bottom) - ABS(pObjRect->top)) / 2);
  913.     middle.h = pObjRect->left
  914.                 + ((ABS(pObjRect->right) - ABS(pObjRect->left)) / 2);
  915.                                 /*    locate pEntryLoc in quadrant            */
  916.     if(pEntryLoc->v>middle.v)
  917.     {                            /*    below the mason-dixon line            */
  918.         pTipLoc->v = pObjRect->bottom - pTipInset->v;
  919.         if(pEntryLoc->h>middle.h)
  920.         {                        /*    southeast quadrant                    */
  921.             pTipLoc->h = pObjRect->right - pTipInset->h;
  922.             if(pTipInset->h>pTipInset->v)
  923.                 *pVariant = kTip0;
  924.             else
  925.                 *pVariant = kTip1;
  926.         }
  927.         else
  928.         {                        /*    southwest quadrant                    */
  929.             pTipLoc->h = pObjRect->left + pTipInset->h;
  930.             if(pTipInset->h>pTipInset->v)
  931.                 *pVariant = kTip3;
  932.             else
  933.                 *pVariant = kTip2;
  934.         }
  935.     }
  936.     else
  937.     {                            /*    above the mason-dixon line            */
  938.         pTipLoc->v = pObjRect->top + pTipInset->v;
  939.         if(pEntryLoc->h>middle.h)
  940.         {                        /*    northeast quadrant                    */
  941.             pTipLoc->h = pObjRect->right - pTipInset->h;
  942.             if(pTipInset->h>pTipInset->v)
  943.                 *pVariant = kTip7;
  944.             else
  945.                 *pVariant = kTip6;
  946.         }
  947.         else
  948.         {                        /*    northwest quadrant                    */
  949.             pTipLoc->h = pObjRect->left + pTipInset->h;
  950.             if(pTipInset->h>pTipInset->v)
  951.                 *pVariant = kTip4;
  952.             else
  953.                 *pVariant = kTip5;
  954.         }
  955.     }    
  956. }    /*    --------------------------------------------    selectBalloon    */
  957.